import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import { ComponentPropsType } from "../../components/QuestionComponents"
import { getNextSelectedId, insertNewComponent } from "./utils"
import cloneDeep from "lodash.clonedeep"
import { nanoid } from "nanoid"
import { arrayMove } from "@dnd-kit/sortable"

export type ComponentInfoType = {
    fe_id: string // 前端生成的 id，服务端 Mongodb 不认这种格式，所以自定义一个fe_id
    type: string
    title: string
    isHidden?: boolean
    isLocked?: boolean
    // 组件属性类型 type ComponentPropsType = QuestionInputPropsType & QuestionTitlePropsType 使用了可选符合，可以使用&
    props: ComponentPropsType
}

// 当前模块纯初的列表的类型
export type ComponentsStateType = {
    selectedId: string
    componentList: ComponentInfoType[]
    copiedComponent: ComponentInfoType | null
}

// 初始化数据
const INIT_STATE: ComponentsStateType = {
    selectedId: "",
    componentList: [],
    // 拷贝组件
    copiedComponent: null
}

export const componentsSlice = createSlice({
    name: "components",
    initialState: INIT_STATE,
    reducers: {
        // 重置所有组件（把组件传进来进行存储）
        resetComponents(state: ComponentsStateType, action: PayloadAction<ComponentsStateType>) {
            return action.payload
        },

        // 修改selectedId
        changeSelectedId(state: ComponentsStateType, action: PayloadAction<string>) {
            state.selectedId = action.payload
        },

        // 添加组件
        addComponent(state: ComponentsStateType, action: PayloadAction<ComponentInfoType>) {
            const newComponent = action.payload

            // 这部分代码逻辑与粘贴组件逻辑相同，故抽离到utils.ts文件中
            // const { selectedId, componentList } = state
            // const index = componentList.findIndex(c => c.fe_id === selectedId)

            // // 未选中组件：在最后添加组件
            // if (index < 0) {
            //     state.componentList.push(newComponent)
            // } else {
            //     // 选中了组件，在选中组件的下方添加组件
            //     state.componentList.splice(index + 1, 0, newComponent)
            // }

            // // 重新设置选中的id
            // state.selectedId = newComponent.fe_id

            insertNewComponent(state, newComponent)
        },

        // 修改组件属性
        changeComponentProps(state: ComponentsStateType, action: PayloadAction<{ fe_id: string; newProps: ComponentPropsType }>) {
            const { fe_id, newProps } = action.payload

            // 找到了当前要修改属性的组件
            const currentComponent = state.componentList.find(c => c.fe_id === fe_id)
            if (currentComponent) {
                currentComponent.props = {
                    ...currentComponent.props,
                    ...newProps
                }
            }
        },

        // 删除选中的组件
        removeSelectedComponent(state: ComponentsStateType) {
            // 不需要传payload的，store存储了选中组件的id
            const { componentList = [], selectedId: removedId } = state // 将selectedId重命名为removedId
            const index = componentList.findIndex(c => c.fe_id === removedId)

            // 重新计算 selectedId
            const newSelectedId = getNextSelectedId(removedId, componentList)
            state.selectedId = newSelectedId

            // 选中了才删除，没选中就不删除
            if (index < 0) return
            componentList.splice(index, 1)
        },

        // 隐藏、显示组件
        changeComponentHidden(state: ComponentsStateType, action: PayloadAction<{ fe_id: string; isHidden: boolean }>) {
            const { componentList = [] } = state
            const { fe_id, isHidden } = action.payload

            // 重新计算 selectedId
            let newSelectedId = ""
            if (isHidden) {
                // 隐藏
                newSelectedId = getNextSelectedId(fe_id, componentList)
            } else {
                // 显示
                newSelectedId = fe_id // fe_id就是要显示的id
            }
            state.selectedId = newSelectedId
            const currentComponent = componentList.find(c => c.fe_id === fe_id)
            if (currentComponent) {
                currentComponent.isHidden = isHidden
            }
        },

        // 切换  锁定、解锁组件
        toggleComponentLocked(state: ComponentsStateType, action: PayloadAction<{ fe_id: string }>) {
            const { fe_id } = action.payload

            const currentComponent = state.componentList.find(c => c.fe_id === fe_id)
            if (currentComponent) {
                currentComponent.isLocked = !currentComponent.isLocked
            }
        },

        // 拷贝当前选中的组件
        copySelectedComponent(state: ComponentsStateType) {
            const { selectedId, componentList = [] } = state
            const selectedComponent = componentList.find(c => c.fe_id === selectedId)

            // 没选中任何组件
            if (selectedComponent == null) return

            // 深拷贝    cloneDeep是一个深拷贝的库
            state.copiedComponent = cloneDeep(selectedComponent)
        },

        // 粘贴组件
        pasteCopiedComponent(state: ComponentsStateType) {
            const { copiedComponent } = state
            // 没有拷贝
            if (copiedComponent == null) return

            // 修改fe_id —— 关键 ！！
            copiedComponent.fe_id = nanoid()

            // 插入copiedComponent （这里和添加组件代码相同，故抽离到utils.ts文件中）
            insertNewComponent(state, copiedComponent)
        },

        // 选中上一个
        selectPrevComponent(state: ComponentsStateType) {
            const { selectedId, componentList } = state
            const selectedIndex = componentList.findIndex(c => c.fe_id === selectedId)

            // 未选中
            if (selectedIndex < 0) return

            if (selectedIndex <= 0) return // 已经选中了第一个，无法再向上选中

            state.selectedId = componentList[selectedIndex - 1].fe_id
        },

        // 选中下一个
        selectNextComponent(state: ComponentsStateType) {
            const { selectedId, componentList } = state
            const selectedIndex = componentList.findIndex(c => c.fe_id === selectedId)

            // 未选中
            if (selectedIndex < 0) return

            if (selectedIndex + 1 === componentList.length) return // 已经选中了最后一个，无法再向下选中

            state.selectedId = componentList[selectedIndex + 1].fe_id
        },

        // 修改组件标题（尖括号中的是一个类型，不是一个对象，并且类型 一行当中要使用分号进行分隔）,要求传入的是一个对象类型
        changeComponentTitle(state: ComponentsStateType, action: PayloadAction<{ fe_id: string; title: string }>) {
            const { title, fe_id } = action.payload
            const currentComponent = state.componentList.find(c => c.fe_id === fe_id)
            if (currentComponent) currentComponent.title = title
        },

        // 移动组件位置（拖拽排序）
        moveComponent(state: ComponentsStateType, action: PayloadAction<{ oldIndex: number; newIndex: number }>) {
            // 修改之前的componentList
            const { componentList: curComponentList } = state

            const { oldIndex, newIndex } = action.payload

            // 也不需要自己写，直接引入库中的方法即可
            state.componentList = arrayMove(curComponentList, oldIndex, newIndex)
        }
    }
})

export const {
    resetComponents,
    changeSelectedId,
    addComponent,
    changeComponentProps,
    removeSelectedComponent,
    changeComponentHidden,
    toggleComponentLocked,
    copySelectedComponent,
    pasteCopiedComponent,
    selectPrevComponent,
    selectNextComponent,
    changeComponentTitle,
    moveComponent
} = componentsSlice.actions
export default componentsSlice.reducer
